package parser;

import java.nio.ByteBuffer;

import osc.OSCMessage;

public class OSCMessageParser {

	private String extractString(ByteBuffer buffer) {
		int position = buffer.position();
		String extracted = null;
		int stringLength = 0;
		// Extracting string
		while (buffer.position() < buffer.capacity() && buffer.get() != 0) {
			stringLength += 1;
		}
		// Skip padding
		buffer.position(buffer.position() - 1);
		extracted = new String(buffer.array(), position, stringLength);
		buffer.position(buffer.position() + 4 - buffer.position() % 4);
		// System.out.println("Extracted string = " + extracted);
		return extracted;
	}

	private Integer extractInteger(ByteBuffer buffer) {
		Integer extracted = buffer.getInt();
		// System.out.println("Extracted integer = " + extracted);
		return extracted;
	}

	private byte[] extractBLOB(ByteBuffer buffer) {
		int size = buffer.getInt();
		byte[] extracted = new byte[size];
		buffer.get(extracted);
		// Skip padding
		buffer.position(buffer.position() + (buffer.position() % 4));
		// System.out.println("Extracted BLOB = " + extracted);
		return extracted;
	}

	private Float extractFloat(ByteBuffer buffer) {
		Float extracted = buffer.getFloat();
		// System.out.println("Extracted float = " + extracted);
		return extracted;
	}

	private void extractParameters(OSCMessage message, ByteBuffer buffer) {

		// Extract template
		String template = extractString(buffer);
		if (template != null && template.length() > 1 && template.charAt(0) == ',') {
			template = template.substring(1);

			Object[] parameters = new Object[template.length()];

			for (int i = 0; i < template.length(); i++) {

				char parameterToRetrieve = template.charAt(i);

				switch (parameterToRetrieve) {
				case OSCMessage.INTEGER:
					parameters[i] = extractInteger(buffer);
					break;
				case OSCMessage.STRING:
					parameters[i] = extractString(buffer);
					break;
				case OSCMessage.FLOAT:
					parameters[i] = extractFloat(buffer);
					break;
				case OSCMessage.BLOB:
					parameters[i] = extractBLOB(buffer);
					break;
				}

			}

			message.setParameters(parameters);
			message.setParametersTemplate(template);
		}
	}

	public OSCMessage parse(byte[] bytes) {
		OSCMessage message = new OSCMessage();
		ByteBuffer buffer = ByteBuffer.wrap(bytes);
		// Extracting target
		message.setTarget(extractString(buffer));
		// Extracting parameters
		extractParameters(message, buffer);
		return message;
	}
}
